package com.demandbreakdown.xiyun.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.demandbreakdown.xiyun.common.annotation.OperationLog;
import com.demandbreakdown.xiyun.common.base.ResultCode;
import com.demandbreakdown.xiyun.common.exception.BusinessException;
import com.demandbreakdown.xiyun.mapper.UserMapper;
import com.demandbreakdown.xiyun.model.dto.auth.ResetPasswordDTO;
import com.demandbreakdown.xiyun.model.dto.user.UserQueryDTO;
import com.demandbreakdown.xiyun.model.dto.user.UserStatusUpdateDTO;
import com.demandbreakdown.xiyun.model.dto.user.UserUpdateDTO;
import com.demandbreakdown.xiyun.model.entity.User;
import com.demandbreakdown.xiyun.model.vo.common.PageVO;
import com.demandbreakdown.xiyun.model.vo.user.UserVO;
import com.demandbreakdown.xiyun.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 用户服务实现类
 *
 * @author poxz
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    // 工具类依赖
    private final PasswordEncoder passwordEncoder;

    @Override
    public UserVO getCurrentUser() {
        Long userId = StpUtil.getLoginIdAsLong();

        User user = this.getById(userId);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_FOUND);
        }

        return UserVO.from(user);
    }

    @Override
    public UserVO getUserById(Long userId) {
        User user = this.getById(userId);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_FOUND);
        }

        return UserVO.from(user);
    }

    @Override
    @OperationLog("更新个人资料")
    @Transactional(rollbackFor = Exception.class)
    public UserVO updateProfile(Long userId, UserUpdateDTO userUpdateDTO) {
        User user = this.getById(userId);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_FOUND);
        }

        // 更新用户信息
        if (StrUtil.isNotBlank(userUpdateDTO.getUserName())) {
            user.setUserName(userUpdateDTO.getUserName());
        }
        if (StrUtil.isNotBlank(userUpdateDTO.getUserProfile())) {
            user.setUserProfile(userUpdateDTO.getUserProfile());
        }
        if (StrUtil.isNotBlank(userUpdateDTO.getUserAvatar())) {
            user.setUserAvatar(userUpdateDTO.getUserAvatar());
        }

        boolean updated = this.updateById(user);
        if (!updated) {
            throw new BusinessException(ResultCode.USER_UPDATE_FAILED);
        }

        return UserVO.from(user);
    }

    @Override
    @OperationLog("重置密码")
    @Transactional(rollbackFor = Exception.class)
    public void resetPassword(Long userId, ResetPasswordDTO resetPasswordDTO) {
        User user = this.getById(userId);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_FOUND);
        }

        // 验证两次新密码是否一致
        if (!resetPasswordDTO.getNewPassword().equals(resetPasswordDTO.getConfirmPassword())) {
            throw new BusinessException(ResultCode.USER_PASSWORD_NOT_MATCH);
        }

        // 验证旧密码
        if (!passwordEncoder.matches(resetPasswordDTO.getOldPassword(), user.getUserPassword())) {
            throw new BusinessException(ResultCode.USER_OLD_PASSWORD_ERROR);
        }

        // 验证新密码不能与旧密码相同
        if (resetPasswordDTO.getOldPassword().equals(resetPasswordDTO.getNewPassword())) {
            throw new BusinessException(ResultCode.USER_PASSWORD_SAME);
        }

        // 更新密码
        user.setUserPassword(passwordEncoder.encode(resetPasswordDTO.getNewPassword()));
        boolean updated = this.updateById(user);
        if (!updated) {
            throw new BusinessException(ResultCode.USER_UPDATE_FAILED);
        }

        // 踢出所有设备（强制重新登录）
        StpUtil.kickout(userId);
    }

    @Override
    public PageVO<UserVO> getUsers(UserQueryDTO userQueryDTO) {
        Page<User> page = new Page<>(userQueryDTO.getCurrent(), userQueryDTO.getSize());

        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StrUtil.isNotBlank(userQueryDTO.getUserAccount()),
                        User::getUserAccount, userQueryDTO.getUserAccount())
                .like(StrUtil.isNotBlank(userQueryDTO.getUserName()),
                        User::getUserName, userQueryDTO.getUserName())
                .eq(StrUtil.isNotBlank(userQueryDTO.getUserRole()),
                        User::getUserRole, userQueryDTO.getUserRole())
                .eq(userQueryDTO.getUserStatus() != null,
                        User::getUserStatus, userQueryDTO.getUserStatus())
                .orderByDesc(User::getCreateTime);

        Page<User> userPage = this.page(page, queryWrapper);
        PageVO<UserVO> pageVO = PageVO.of(userPage, UserVO::from);

        return pageVO;
    }

    @Override
    @OperationLog(value = "更新用户状态", params = {"#userId", "#userStatusUpdateDTO.userStatus"})
    @Transactional(rollbackFor = Exception.class)
    public void updateUserStatus(Long userId, UserStatusUpdateDTO userStatusUpdateDTO) {
        User user = this.getById(userId);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_FOUND);
        }

        Integer oldStatus = user.getUserStatus();
        Integer newStatus = userStatusUpdateDTO.getUserStatus();

        user.setUserStatus(newStatus);
        boolean updated = this.updateById(user);
        if (!updated) {
            throw new BusinessException(ResultCode.USER_UPDATE_FAILED);
        }

        // 处理状态变更的影响
        if (newStatus == 0) {
            handleUserDisabled(userId, user.getUserAccount());
        } else if (oldStatus == 0 && newStatus == 1) {
            handleUserEnabled(userId, user.getUserAccount());
        }
    }

    /**
     * 处理用户被禁用的影响
     */
    private void handleUserDisabled(Long userId, String userAccount) {
        try {
            StpUtil.kickout(userId);
            log.info("用户被禁用并踢出: userId={}, 账号={}", userId, userAccount);

            // TODO: 扩展功能
            // - 暂停用户的定时任务
            // - 清理用户的缓存信息
            // - 发送邮件通知用户
            // - 冻结用户的资源（图片、空间等）

        } catch (Exception e) {
            log.error("处理用户禁用影响失败: userId={}, error={}", userId, e.getMessage());
        }
    }

    /**
     * 处理用户被重新启用的影响
     */
    private void handleUserEnabled(Long userId, String userAccount) {
        try {
            log.info("用户被重新启用: userId={}, 账号={}", userId, userAccount);

            // TODO: 扩展功能
            // - 恢复用户的定时任务
            // - 发送欢迎回归的邮件通知
            // - 解冻用户的资源

        } catch (Exception e) {
            log.error("处理用户启用影响失败: userId={}, error={}", userId, e.getMessage());
        }
    }
}